import difflib
from typing import List, Tuple
from docx import Document
from docx.enum.text import WD_COLOR_INDEX
from docx.oxml.shared import OxmlElement
from docx.oxml.ns import qn
import re
class DocxParaContent:
    def __init__(self, para,s_index = 0,e_index=0):
        self.para = para
        self.s_index = s_index
        self.e_index = e_index if e_index else len(para.text)
        self.text = para.text[s_index:self.e_index]

class Operation:
    def __init__(self,type:str,change_index:int,origin_content = "",new_content = ""):
        self.origin_content = origin_content
        self.new_content = new_content
        self.type = type
        self.change_index = change_index

    @classmethod
    def from_dict(cls, data):
        return cls(**data)
def read_docx(file_path)->Tuple[List[DocxParaContent], Document]:
    ''''
    读取docx文件，划分段落
    '''
    doc = Document(file_path)
    content = []
    for para in doc.paragraphs:
        # 检查段落长度
        if len(para.text) > 800:
            # 分割长段落
            content.extend(split_paragraph(para.text))
        else:
            content.append(DocxParaContent(
                para=para
            ))
    return content,doc

def split_paragraph(paragraph_text, max_length=800):
    '''划分段落'''
    # 使用正则表达式匹配所有句子
    sentences = re.split(r'(?<=[。！？])', paragraph_text)
    # 用来存储处理后的段落
    new_paragraphs = []
    current_paragraph = ""

    for sentence in sentences:
        # 检查当前段落长度是否超过最大长度
        if len(current_paragraph) + len(sentence) > max_length:
            # 如果超过了，先存储当前段落
            new_paragraphs.append(current_paragraph)
            # 开始一个新段落
            current_paragraph = sentence
        else:
            # 如果没有超过，继续添加句子到当前段落
            current_paragraph += sentence

    # 添加最后一个段落，如果有内容的话
    if current_paragraph:
        new_paragraphs.append(current_paragraph)

    return new_paragraphs
def text_diff_operations(original, modified):
    '''比对文本差异'''
    sequence_matcher = difflib.SequenceMatcher(None, original, modified)
    operations = []
    def build_insertion(idx, content):
        return {'type': 'insert', 'origin_content': '', 'new_content': content, 'change_index': idx}
    
    def build_replaceation(idx, original, new):
        return {'type': 'replace', 'origin_content': original, 'new_content': new, 'change_index': idx}

    def build_deletion(idx, content):
        return {'type': 'delete', 'origin_content': content, 'new_content': '', 'change_index': idx}

    index_shift = 0
    for tag, i1, i2, j1, j2 in sequence_matcher.get_opcodes():
        if tag == 'equal':
            continue

        original_fragment = original[i1:i2]
        modified_fragment = modified[j1:j2]
        if tag == 'replace':
            # Check if replacement can be merged into a single change (often more readable)
            if len(original_fragment) == len(modified_fragment):
                for k in range(len(original_fragment)):
                    operations.append(build_replaceation(i1 + k + index_shift, original_fragment[k], modified_fragment[k]))
            else:
                operations.append(build_replaceation(i1 + index_shift, original_fragment, modified_fragment))
        elif tag == 'insert':
            operations.append(build_insertion(i1 + index_shift, modified_fragment))
            # index_shift += len(modified_fragment)  # Adjust future indexes due to insertion
        elif tag == 'delete':
            operations.append(build_deletion(i1 + index_shift, original_fragment))
            # index_shift -= len(original_fragment)  # Adjust future indexes due to deletion
    
    return operations


def add_strikethrough(run):
    """给文本添加删除线"""
    rPr = run._r.get_or_add_rPr()
    strike = OxmlElement('w:strike')
    strike.set(qn('w:val'), 'true')
    rPr.append(strike)

def modify_paragraph(content:DocxParaContent,operations:list[Operation]):
    '''修改段落'''
    para = content.para
    # if operation.change_index + len(operation.origin_content) <= len(para.text):
    operations.sort(key=lambda x: x['change_index'], reverse=True)  # 从后向前处理，避免索引错乱
    original_text = para.text
    # 清除段落内容，然后重新构建
    para.clear()
    print(original_text)
    current_index = 0
    for op in sorted(operations, key=lambda x: x['change_index']):  # 重新排序以按文本顺序插入
        operation = Operation.from_dict(op)
        change_index = operation.change_index
        origin_content = operation.origin_content
        new_content = operation.new_content
        
        # 添加未修改的文本
        if current_index < change_index:
            print(original_text[current_index:change_index])
            para.add_run(original_text[current_index:change_index])
        
        if len(origin_content):
            # 添加带删除线的原始内容
            run_with_strikethrough = para.add_run(origin_content)
            run_with_strikethrough.font.highlight_color = WD_COLOR_INDEX.RED
            add_strikethrough(run_with_strikethrough)
        
        if len(new_content):
            # 添加新内容并高亮
            run_with_highlight = para.add_run(new_content)
            run_with_highlight.font.highlight_color = WD_COLOR_INDEX.YELLOW
        
        # 更新当前索引
        current_index = change_index + len(origin_content)

    # 添加剩余的文本
    if current_index < len(original_text):
        para.add_run(original_text[current_index:])

# Example texts
original = '妈妈说："我看了一本书，书名叫呐喊."'
modified = '妈妈说：“我看完了一本书，书名叫《呐喊》。”'

# Getting the difference
diffs = text_diff_operations(original, modified)
print(diffs)
